home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Imaging / Matrix.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  24.7 KB  |  876 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Matrix.cpp
  3.  
  4.     Contains:    Matrix math for ODTransforms.
  5.  
  6.     Owned by:    Jens Alfke
  7.     Owned by:    Cary Clark, Michael Fairman, Robert Johnson, Keith McGreggor,
  8.                 Oliver Steele, David Van Brink, Jens Alfke
  9.     Based on:    QuickDraw GX "matrixMath.c" and "math.c" sources
  10.  
  11.     Copyright:    © 1994 - 1995 by Apple Computer, Inc., all rights reserved.
  12.  
  13.     Change History (most recent first):
  14.     
  15.          <2>     5/25/95    jpa        Renamed some routines that conflict with GX
  16.                                     exports. [1241078, 1253324]
  17.          <1>     6/15/94    jpa        first checked in
  18.          ---------------------------Moved to ODSOM project.
  19.          <2>     5/10/94    jpa        Replaced a too-complex typecast to appease
  20.                                     %$*# cfront.
  21.          <1>      5/9/94    jpa        first checked in
  22.     To Do:
  23.         * I have no idea whether this code will work on little-endian CPUs.
  24.           It _should_, but who knows?
  25.     In Progress:
  26.         
  27. */
  28.  
  29.  
  30. #pragma segment ODTransform
  31.  
  32.  
  33. #ifndef _MATRIX_
  34. #include "Matrix.h"
  35. #endif
  36.  
  37. #ifndef _ODMATH_
  38. #include "ODMath.h"
  39. #endif
  40.  
  41.  
  42. //=============================================================================
  43. // Constants & Types
  44. //=============================================================================
  45.  
  46.  
  47. #define wideSize        64                        /* bit sizes */
  48. #define longSize        32
  49. #define fractPrecision    30                        /* fixed ODPoint precisions */
  50. #define fixedPrecision    16
  51.  
  52.  
  53. typedef int fastInt;
  54.  
  55.  
  56. const ODMatrix kODIdentityMatrix = {{{kODFixed1, 0, 0},
  57.                                        {0, kODFixed1, 0},
  58.                                        {0,  0, kODFract1}}};
  59.  
  60.  
  61. //=============================================================================
  62. // Math Subroutines
  63. //=============================================================================
  64.  
  65. // MyWideScale is the same as GX's WideScale.
  66.  
  67. static ODSShort
  68. MyWideScale( const ODWide *wide )    // JPA: I wrote this from scratch
  69. {
  70.     ODWide temp = *wide;
  71.     if (temp.hi < 0)
  72.         ODWideNegate(&temp);
  73.     if (temp.hi)
  74.         return ODFirstBit(temp.hi) + longSize;
  75.     else
  76.         return ODFirstBit(temp.lo);
  77. }
  78.  
  79.  
  80. #if PLATFORM_MACINTOSH && USES68KINLINES
  81.     /* an inline macro version of overflow checking: */
  82.     extern "C" {
  83.         #pragma parameter __D0 FixAddCheck(__D0, __A0)
  84.         extern ODBoolean FixAddCheck( ODFixed a, ODFixed *b ) = {
  85.             0xD190,        // ADD.L    D0,(A0)
  86.             0x58C0,        // SVC        D0        0 if overflow, 0xff if no overflow
  87.             0x5200      // ADDQ.B    #$1,D0    1 if overflow, 0 if no overflow
  88.         };
  89.     }
  90. #else
  91.     static ODBoolean
  92.     FixAddCheck( ODFixed a, ODFixed *b )
  93.     {
  94.         register ODFixed temp = *b;
  95.         
  96.         *b += a;
  97.         if (*b < temp ^ a < 0)
  98.             return true;
  99.         else
  100.             return false;
  101.     }
  102. #endif
  103.  
  104.  
  105. static ODBoolean
  106. FixMulCheck( ODFixed a, ODFixed b, ODFixed *result )
  107. {
  108.     *result = ODFixedMultiply(a,b);
  109.     return (*result==kODFixedInfinity || *result==kODFixedMinusInfinity);
  110. }
  111.  
  112.  
  113. static ODBoolean
  114. FixDivCheck( ODFixed a, ODFixed b, ODFixed *result )
  115. {
  116.     *result = ODFixedDivide(a,b);
  117.     return (*result==kODFixedInfinity || *result==kODFixedMinusInfinity);
  118. }
  119.  
  120.  
  121. static ODBoolean
  122. FixMulAddCheck(register ODFixed a, register ODFixed b, register ODFixed *c)
  123. {
  124.     ODWide temp;
  125.     ODWideShift(ODWideMultiply(a, b, &temp), fixedPrecision);
  126.     if (*c < 0) --temp.hi;
  127.     temp.lo += *c;
  128.     if (temp.lo < *c) ++temp.hi;
  129.     *c = temp.lo;
  130.     return !ODWideIsLong(&temp);
  131. }
  132.  
  133.  
  134. static ODBoolean
  135. MulMulAddCheck( long a1, long b1, long a2, long b2, short bias, long *dest )
  136. {
  137.     ODWide temp1, temp2;
  138.     ODWideShift(ODWideAdd(ODWideMultiply(a1, b1, &temp1),
  139.                              ODWideMultiply(a2, b2, &temp2)),
  140.                  bias);
  141.     if (*dest < 0) --temp1.hi;
  142.     if ((temp1.lo += *dest) < *dest) ++temp1.hi;
  143.     *dest = temp1.lo;
  144.     return !ODWideIsLong(&temp1);
  145. }
  146.  
  147.  
  148. static ODBoolean
  149. FracDivCheck(register ODFixed dividend, register ODFixed divisor, register ODFixed *dest)
  150. {
  151.     ODWide temp;
  152.     temp.hi = dividend; temp.lo = 0;
  153.     *dest = ODWideDivide(ODWideShift(&temp, longSize-fractPrecision), divisor, kODIgnoreRemainder);
  154.     return *dest == kODFixedMinusInfinity;
  155. }
  156.  
  157.  
  158. static ODBoolean
  159. FracMulAddCheck(register ODFixed a, register ODFixed b, register ODFixed *c)
  160. {
  161.     ODWide temp;
  162.     ODWideShift(ODWideMultiply(a, b, &temp), fractPrecision);
  163.     if (*c < 0) --temp.hi;
  164.     temp.lo += *c;
  165.     if (temp.lo < *c) ++temp.hi;
  166.     *c = temp.lo;
  167.     return !ODWideIsLong(&temp);
  168. }
  169.  
  170.  
  171. static ODBoolean
  172. FracDivAddCheck(register ODFixed a, register ODFixed b, register ODFixed *c)
  173. {
  174.     ODFixed d;
  175.     return FracDivCheck(a, b, &d) || FixAddCheck(d, c);
  176. }
  177.  
  178.  
  179. // MyVectorMultiply is the same as GX's VectorMultiply. Ditto the ...Divide variant.
  180.  
  181. static ODWide*
  182. MyVectorMultiply(register long count, register const long *vector1, register long step1,
  183.                 register const long *vector2, register long step2, register ODWide *dot)
  184. {
  185.     short flags = count >= 0;
  186.     dot->hi = dot->lo = 0;
  187.     if (!flags)
  188.         count = -count;
  189.     while (count--)
  190.     {    ODWide temp;
  191.         if (flags ^= 2)
  192.             ODWideAdd(dot, ODWideMultiply(*vector1, *vector2, &temp));
  193.         else
  194.             ODWideSubtract(dot, ODWideMultiply(*vector1, *vector2, &temp));
  195.         vector1 += step1;
  196.         vector2 += step2;
  197.     }
  198.     return dot;
  199. }
  200.  
  201.  
  202. static long
  203. MyVectorMultiplyDivide(long count, const long *vector1, long step1,
  204.                                  const long *vector2, long step2, long scalar)
  205. {
  206.     ODWide temp;
  207.     return ODWideDivide(MyVectorMultiply(count, vector1, step1, vector2, step2, &temp), scalar, 0);
  208. }
  209.  
  210.  
  211.  
  212. //=============================================================================
  213. // Matrix Math
  214. //=============================================================================
  215.  
  216.  
  217. ODTransformType
  218. MxType(const ODMatrix *matrix)
  219. {
  220.     register ODSShort translate;
  221.  
  222.     if (matrix->m[0][2] == 0 && matrix->m[1][2] == 0 && matrix->m[2][2] <= 0)
  223.         return kODInvalidXform;
  224.     if (matrix->m[0][2] || matrix->m[1][2] || matrix->m[2][2] != kODFract1)
  225.         return kODPerspectiveXform;
  226.     if (matrix->m[2][0] || matrix->m[2][1])
  227.         translate = kODTranslateXform;
  228.     else
  229.         translate = kODIdentityXform;
  230.     if (matrix->m[0][1] || matrix->m[1][0])
  231.         return (ODTransformType)( (ODSShort)kODLinearXform + translate );
  232.     if (matrix->m[0][0] != kODFixed1 || matrix->m[1][1] != kODFixed1)
  233.         return (ODTransformType)( (ODSShort)kODScaleXform + translate );
  234.     return (ODTransformType)translate;
  235. }
  236.  
  237.  
  238. ODBoolean
  239. MxNormalize(ODMatrix *map)
  240. {
  241.     unsigned long norm[3][3];
  242.     register fastInt shift, count;
  243.     register ODFixed *src;
  244.     register unsigned long *dst;
  245.     ODTransformType state = MxType(map);
  246.  
  247.     if (state == kODInvalidXform) return true;
  248.     if (state != kODPerspectiveXform) return false;            /* map is already normalized */
  249.  
  250.     {    register unsigned long mask = 0;
  251.         src = &map->m[0][0]; dst = &norm[0][0];
  252.         count = 9;
  253.         do
  254.         {    register ODFixed temp;
  255.             if ((temp = *src++) < 0) temp = -temp;
  256.             mask |= *dst++ = temp;
  257.         } while (--count);
  258.         shift = ODFirstBit(mask) - fractPrecision;            /* find the scale of greatest element */
  259.     }
  260.  
  261.     src = &map->m[0][0];
  262.     {    register unsigned long sum;
  263.         register ODFract w;
  264.         if ( (sum = norm[0][2] + norm[1][2]) != 0 )                /* map is truly perspective */
  265.         {    count = ODFirstBit(sum) - (fractPrecision - 1);
  266.             if (count >= 0 ? sum > kODFract1 - kODFixed1 << count : sum << -count > kODFract1 - kODFixed1) ++count;
  267.             if (count > shift) shift = count;
  268.         }
  269.         else                                        /* map is pathologically affine */
  270.         {    w = map->m[2][2];                    /* must be > 0 or map would be invalid */
  271.             if (w & w - 1)                            /* if it's not a power of 2, try to divide by w */
  272.             {    count = 3;
  273.                 dst = &norm[0][0];
  274.                 do                                /* check if map can be divided by w */
  275.                 {    if (*dst++ >> 1 >= w ) break;        /* is the x-coefficient too big? */
  276.                     if (*dst++ >> 1 >= w ) break;        /* is the y-coefficient too big? */
  277.                 } while (++dst, --count);
  278.                 if (count == 0)                        /* no coefficients were too big */
  279.                 {    count = 3;
  280.                     do
  281.                     {    *src = FracDiv(*src, w); ++src;    /* divide the x-coefficient by w */
  282.                         *src = FracDiv(*src, w); ++src;    /* divide the y-coefficient by w */
  283.                     } while (++src, --count);
  284.                     map->m[2][2] = kODFract1;
  285.                     return false;
  286.                 }
  287.             }
  288.         }
  289.     }
  290.  
  291.     /*    if map is truly perspective, w is a power of 2, or map cannot be divided by w,
  292.         shift map so that either the scale of some element is fractPrecision or
  293.         the L1 norm of u and v does not exceed kODFract1 - kODFixed1.  This insures that
  294.             FractMultiply(u, x) + FractMultiply(v, y) + FractToFixed(w)
  295.         never overflows.
  296.     */
  297.     count = 9;
  298.     if (shift > 0)
  299.     {    register ODFixed round = 1 << shift - 1;
  300.         do *src = *src + round >> shift;
  301.         while (++src, --count);
  302.     }
  303.     else if ( (shift = -shift) != 0 )
  304.         do *src <<= shift;
  305.         while (++src, --count);
  306.     return false;
  307. }
  308.  
  309.  
  310. typedef struct
  311. {    char bits[2][2];
  312. } bias;
  313.  
  314.  
  315. static ODBoolean
  316. MxWideNorm(ODWide src[3][3], ODMatrix *dst, register bias *delta)
  317. {
  318.     ODWide norm[3][3];
  319.     register fastInt shift;
  320.     register long hi;
  321.     register unsigned long lo;
  322.     register long *srcPtr, *dstPtr;
  323.  
  324.     {    register fastInt count;
  325.  
  326.                 /* Compute the absolute values of src */
  327.         srcPtr = (long *)&src[0][0]; dstPtr = (long *)&norm[0][0];
  328.         count = 9;
  329.         do
  330.         {    hi = *srcPtr++; lo = *srcPtr++;
  331.             if (hi < 0)
  332.                 (lo = -lo)!=0 ? (hi = ~hi) : (hi = -hi);
  333.             *dstPtr++ = hi; *dstPtr++ = lo;
  334.         } while (--count);
  335.  
  336.                 /* Find the scale of a, b, c, and d */
  337.         if ( (hi = norm[0][0].hi | norm[0][1].hi | norm[1][0].hi | norm[1][1].hi) != 0 )
  338.             shift = ODFirstBit(hi) + longSize - fractPrecision - delta->bits[0][0];
  339.         else if ( (lo = norm[0][0].lo | norm[0][1].lo | norm[1][0].lo | norm[1][1].lo) != 0 )
  340.             shift = ODFirstBit(lo) - fractPrecision - delta->bits[0][0];
  341.         else shift = -wideSize;
  342.  
  343.                 /* Find the scale of u and v */
  344.         if ( (hi = norm[0][2].hi | norm[1][2].hi) != 0 )
  345.             count = ODFirstBit(hi) + longSize - fractPrecision - delta->bits[0][1];
  346.         else if ( (lo = norm[0][2].lo | norm[1][2].lo) != 0 )
  347.             count = ODFirstBit(lo) - fractPrecision - delta->bits[0][1];
  348.         else count = -wideSize;
  349.         if (count > shift) shift = count;
  350.  
  351.                 /* Find the scale of h and k */
  352.         if ( (hi = norm[2][0].hi | norm[2][1].hi) != 0 )
  353.             count = ODFirstBit(hi) + longSize - fractPrecision - delta->bits[1][0];
  354.         else if ( (lo = norm[2][0].lo | norm[2][1].lo) != 0 )
  355.             count = ODFirstBit(lo) - fractPrecision - delta->bits[1][0];
  356.         else count = -wideSize;
  357.         if (count > shift) shift = count;
  358.  
  359.                 /* Find the scale of w */
  360.         if ( (hi = norm[2][2].hi) != 0 )
  361.             count = ODFirstBit(hi) + longSize - fractPrecision - delta->bits[1][1];
  362.         else if ( (lo = norm[2][2].lo) != 0 )
  363.             count = ODFirstBit(lo) - fractPrecision - delta->bits[1][1];
  364.         else count = -wideSize;
  365.         if (count > shift) shift = count;
  366.     }
  367.  
  368.     {    register fastInt i, j;
  369.  
  370.                 /* Execute the shift */
  371.         srcPtr = (long *)&src[0][0]; dstPtr = &dst->m[0][0];
  372.         for (i = 3; i--; )
  373.             for (j = 3; j--; )
  374.             {    ODWide temp;
  375.                 temp.hi = *srcPtr++; temp.lo = *srcPtr++;
  376.                 ODWideShift(&temp, shift + delta->bits[!i ][!j]);
  377.                 *dstPtr++ = temp.lo;
  378.             }
  379.     }
  380.     return MxNormalize(dst);
  381. }
  382.  
  383.  
  384. /*    MxInverse - Computes the inverse of the given matrix, placing it in the destination (second) matrix. */
  385. ODBoolean
  386. MxInverse(const ODMatrix *matrix, register ODTransformType flags, ODMatrix *imatrix)
  387. {
  388.     register ODFixed *im = &imatrix->m[0][0];
  389.     register const ODFixed *m0 = &matrix->m[0][0];
  390.  
  391.     switch(flags) {
  392.         case kODIdentityXform:
  393.             *imatrix = *matrix;                /* do nothing but copy if identity */
  394.         break;
  395.         case kODTranslateXform:
  396.         {
  397.             *im++ = *m0++;                                            /* a = 1.0 */
  398.             *im++ = *m0++;                                            /* b = 0.0 */
  399.             *im++ = *m0++;                                            /* u = 0.0 */
  400.             *im++ = *m0++;                                            /* c = 0.0 */
  401.             *im++ = *m0++;                                            /* d = 1.0 */
  402.             *im++ = *m0++;                                            /* v = 0.0 */
  403.             *im++ = -*m0++;                                            /* h = -h */
  404.             *im++ = -*m0++;                                            /* k = -k */
  405.             *im = *m0;                                                /* w = 1.0 */
  406.         }
  407.         break;
  408.         case kODScaleXform:
  409.         case kODScaleXform+kODTranslateXform:
  410.         {    ODFixed temp;
  411.             register ODFixed a, d;
  412.             if (FixDivCheck(kODFixed1, a = *m0++, &temp)) return true; *im++ = temp;    /* a = 1/a */
  413.             *im++ = *m0++;                                            /* b = 0.0 */
  414.             *im++ = *m0++;                                            /* u = 0.0 */
  415.             *im++ = *m0++;                                            /* c = 0.0 */
  416.             if (FixDivCheck(kODFixed1, d = *m0++, &temp)) return true; *im++ = temp;    /* d = 1/d */
  417.             *im++ = *m0++;                                            /* v = 0.0 */
  418.             if (flags & kODTranslateXform)
  419.             {    if (FixDivCheck(*m0++, a, &temp)) return true; *im++ = -temp;    /* h = -h/a */
  420.                 if (FixDivCheck(*m0++, d, &temp)) return true; *im++ = -temp;    /* k = -k/d */
  421.             }
  422.             else
  423.             {    *im++ = *m0++;                                        /* h = 0.0 */
  424.                 *im++ = *m0++;                                        /* k = 0.0 */
  425.             }
  426.             *im = *m0;                                                /* w = 1.0 */
  427.         }
  428.         break;
  429.         case kODLinearXform:
  430.         case kODLinearXform+kODTranslateXform:
  431.         {    ODWide det, temp, tmp;
  432.             register short shift;
  433.  
  434.             /* compute the determinant */
  435.             ODWideSubtract(ODWideMultiply(matrix->m[0][0], matrix->m[1][1], &det),
  436.                     ODWideMultiply(matrix->m[1][0], matrix->m[0][1], &temp));
  437.             if ((shift = MyWideScale(&det) - (longSize - 2)) > 0)
  438.                 ODWideShift(&det, shift);
  439.             else
  440.                 shift = 0;
  441.  
  442.             temp.hi = matrix->m[1][1]; temp.lo = 0;
  443.             if ((*im++ = ODWideDivide(ODWideShift(&temp, shift), det.lo, kODIgnoreRemainder)) == kODFixedMinusInfinity)
  444.                 return true;
  445.             temp.hi = -matrix->m[0][1]; temp.lo = 0;
  446.             if ((*im++ = ODWideDivide(ODWideShift(&temp, shift), det.lo, kODIgnoreRemainder)) == kODFixedMinusInfinity)
  447.                 return true;
  448.             *im++ = 0;
  449.             temp.hi = -matrix->m[1][0]; temp.lo = 0;
  450.             if ((*im++ = ODWideDivide(ODWideShift(&temp, shift), det.lo, kODIgnoreRemainder)) == kODFixedMinusInfinity)
  451.                 return true;
  452.             temp.hi = matrix->m[0][0]; temp.lo = 0;
  453.             if ((*im++ = ODWideDivide(ODWideShift(&temp, shift), det.lo, kODIgnoreRemainder)) == kODFixedMinusInfinity)
  454.                 return true;
  455.             *im++ = 0;
  456.             if (flags & kODTranslateXform)
  457.             {    shift -= fixedPrecision;
  458.                 ODWideSubtract(ODWideMultiply(matrix->m[1][0], matrix->m[2][1], &temp), ODWideMultiply(matrix->m[2][0], matrix->m[1][1], &tmp));
  459.                 if (shift < MyWideScale(&temp) - (wideSize - 2))
  460.                     return true;
  461.                 if ((*im++ = ODWideDivide(ODWideShift(&temp, shift), det.lo, kODIgnoreRemainder)) == kODFixedMinusInfinity)
  462.                     return true;
  463.                 ODWideSubtract(ODWideMultiply(matrix->m[0][1], matrix->m[2][0], &temp), ODWideMultiply(matrix->m[2][1], matrix->m[0][0], &tmp));
  464.                 if (shift < MyWideScale(&temp) - (wideSize - 2))
  465.                     return true;
  466.                 if ((*im++ = ODWideDivide(ODWideShift(&temp, shift), det.lo, kODIgnoreRemainder)) == kODFixedMinusInfinity)
  467.                     return true;
  468.             }
  469.             else
  470.             {    *im++ = 0;
  471.                 *im++ = 0;
  472.             }
  473.             *im++ = kODFract1;
  474.         }
  475.         break;
  476.         case kODPerspectiveXform:
  477.         {    ODWide inv[3][3];
  478.             ODWide temp;
  479.             bias delta = { 30, 16, 16, 2 };
  480.  
  481.             ODWideSubtract(ODWideMultiply(m0[4], m0[8], &inv[0][0]), ODWideMultiply(m0[5], m0[7], &temp));
  482.             ODWideSubtract(ODWideMultiply(m0[2], m0[7], &inv[0][1]), ODWideMultiply(m0[1], m0[8], &temp));
  483.             ODWideSubtract(ODWideMultiply(m0[1], m0[5], &inv[0][2]), ODWideMultiply(m0[2], m0[4], &temp));
  484.             ODWideSubtract(ODWideMultiply(m0[5], m0[6], &inv[1][0]), ODWideMultiply(m0[3], m0[8], &temp));
  485.             ODWideSubtract(ODWideMultiply(m0[0], m0[8], &inv[1][1]), ODWideMultiply(m0[6], m0[2], &temp));
  486.             ODWideSubtract(ODWideMultiply(m0[2], m0[3], &inv[1][2]), ODWideMultiply(m0[0], m0[5], &temp));
  487.             ODWideSubtract(ODWideMultiply(m0[3], m0[7], &inv[2][0]), ODWideMultiply(m0[6], m0[4], &temp));
  488.             ODWideSubtract(ODWideMultiply(m0[6], m0[1], &inv[2][1]), ODWideMultiply(m0[0], m0[7], &temp));
  489.             ODWideSubtract(ODWideMultiply(m0[0], m0[4], &inv[2][2]), ODWideMultiply(m0[3], m0[1], &temp));
  490.  
  491.             return MxWideNorm(inv, imatrix, &delta);
  492.         }
  493.         break;
  494.         case kODUnknownXform:
  495.         case kODInvalidXform:
  496.             return true;
  497.     }
  498.     return false;
  499. }
  500.  
  501.  
  502. /*    MxMul multiples a list of vectors by the given matrix and returns the result in place.
  503.     ( x1 y1 1 ) = ( x0 y0 1 ) * matrix;    */
  504. ODBoolean
  505. MxMul(const ODMatrix *matrix, ODTransformType flags, ODPoint *vector, ODSLong cnt)
  506. {
  507.     register const ODFixed *m0 = matrix->m[0];
  508.     register ODFixed *vectorPtr = &vector->x;
  509.     register ODSLong count = cnt;
  510.     
  511.     switch(flags) {  /* do nothing if identity matrix */
  512.         case kODTranslateXform:
  513.             m0 += 6;  /* advance to x translate */
  514.             {    register ODFixed x = *m0++;  /* x translation */
  515.                 register ODFixed y = *m0;  /* y translation */
  516.                     
  517.                 while (count--)
  518.                 {    if (FixAddCheck(x, vectorPtr))
  519.                         goto MxMulError;
  520.                     ++vectorPtr;
  521.                     if (FixAddCheck(y, vectorPtr))
  522.                         goto MxMulError;
  523.                     ++vectorPtr;
  524.                 }
  525.             }
  526.         break;
  527.         case kODScaleXform:
  528.             {    register ODFixed xScale = *m0; 
  529.                 register ODFixed yScale = *(m0 + 4);
  530.                     
  531.                 while (count--)
  532.                 {    ODFixed temp;
  533.                 
  534.                     if (FixMulCheck(*vectorPtr, xScale, &temp))
  535.                         goto MxMulError;
  536.                     *vectorPtr++ = temp;
  537.                     if (FixMulCheck(*vectorPtr, yScale, &temp))
  538.                         goto MxMulError;
  539.                     *vectorPtr++ = temp;
  540.                 }
  541.             }
  542.         break;
  543.         case kODTranslateXform + kODScaleXform:
  544.             {    register ODFixed xScale = *m0;
  545.                 register ODFixed yScale = *(m0 + 4);
  546.                 register ODFixed x, y;
  547.                     
  548.                 m0 += 6;  /* advance to x translate */
  549.                 x = *m0++;  /* x translation */
  550.                 y = *m0;  /* y translation */
  551.                 while (count--)
  552.                 {    ODFixed tempX = *vectorPtr, tempY = *(vectorPtr + 1);
  553.                     *vectorPtr = x;
  554.                     if (FixMulAddCheck(xScale, tempX, vectorPtr))
  555.                         goto MxMulError;
  556.                     *++vectorPtr = y;
  557.                     if (FixMulAddCheck(yScale, tempY, vectorPtr))
  558.                         goto MxMulError;
  559.                     ++vectorPtr;
  560.                 }
  561.             }
  562.         break;
  563.         case kODLinearXform:
  564.         case kODLinearXform + kODTranslateXform:
  565.             {    register const ODFixed *m1;    /* will ODPoint at y translation vector */
  566.                 register ODFixed xScale = *m0;
  567.                 register ODFixed alpha = *(m0 += 1);
  568.                 register ODFixed beta = *(m0 += 2);
  569.                 register ODFixed yScale = *(m0 += 1);
  570.                 register ODFixed xTemp, yTemp;
  571.                 
  572.                 m0 += 2; /* ODPoint at x translation vector */
  573.                 m1 = m0 + 1;
  574.                 
  575.                 while (count--)
  576.                 {    xTemp = *vectorPtr, yTemp = *(vectorPtr + 1);
  577.                     *vectorPtr = *m0;
  578.                     if (MulMulAddCheck(xTemp, xScale, yTemp, beta, fixedPrecision, vectorPtr))
  579.                         goto MxMulError;
  580.                     *++vectorPtr = *m1;
  581.                     if (MulMulAddCheck(xTemp, alpha, yTemp, yScale, fixedPrecision, vectorPtr))
  582.                         goto MxMulError;
  583.                     ++vectorPtr;
  584.                 }
  585.             }
  586.         break;
  587.         case kODPerspectiveXform:
  588.             {    register ODFixed *dst = vectorPtr;
  589.                 register ODFixed m, divisor;
  590.                 register ODFract u, v;
  591.                 ODFixed cpy[3];
  592.                 cpy[2] = kODFixed1;
  593.                 u = m0[2];
  594.                 v = m0[5];
  595.                 m = ODFractToFixed(m0[8]);
  596.                 while (count--)
  597.                 {    divisor = FracMul(u, vectorPtr[0]) + FracMul(v, vectorPtr[1]) + m;
  598.                     if (divisor <= 0)
  599.                         goto MxMulError;
  600.                     cpy[0] = *vectorPtr++;
  601.                     cpy[1] = *vectorPtr++;
  602.                     *dst++ = MyVectorMultiplyDivide(3, cpy, 1, m0, 3, divisor);
  603.                     *dst++ = MyVectorMultiplyDivide(3, cpy, 1, m0+1, 3, divisor);
  604.                 }
  605.             }
  606.         break;
  607.         case kODUnknownXform:
  608.         case kODInvalidXform:
  609.         MxMulError:
  610.             return true;
  611.     }  /* end of switch */
  612.     return false;
  613. }
  614.  
  615.  
  616. /*    MxMulOffset - Multiples a list of vectors by the given matrix and returns the result in place.
  617.     ( x1 y1 1 ) = ( x0-hOffset y0-vOffset 1 ) * matrix;    */
  618. static ODBoolean
  619. MxMulOffset(const ODMatrix *matrix, ODTransformType flags, ODPoint *vector, ODSLong cnt, ODFixed hOffset, ODFixed vOffset)
  620. {
  621.     register ODFixed *vectorPtr = &vector->x;
  622.     register ODFixed h = hOffset, v = vOffset;
  623.  
  624.     if (h || v)
  625.     {    ODMatrix translation;
  626.         ODBoolean error;
  627.         translation.m[2][0] = -h;
  628.         translation.m[2][1] = -v;
  629.         error = MxMul(&translation, kODTranslateXform, vector, cnt);
  630.         if( error ) return error;
  631.     }
  632.     return MxMul(matrix, flags, vector, cnt);
  633. }
  634.  
  635.  
  636. /* MxConcat - Postmultiplies matrix B by matrix A.
  637.     B = B * A;
  638.      returns true if error occurs (either invalid matrix or overflow in calculation)
  639.  */
  640. ODBoolean
  641. MxConcat(register const ODMatrix *a, register ODTransformType aFlags,
  642.          register ODMatrix *b, register ODTransformType bFlags)
  643. {
  644.     ODBoolean savedB = false;
  645.     ODMatrix oldB;
  646.  
  647.     if (aFlags == kODUnknownXform && (aFlags = MxType(a)) == kODInvalidXform)
  648.         return true;
  649.     if (bFlags == kODUnknownXform && (bFlags = MxType(b)) == kODInvalidXform)
  650.         return true;
  651.     if (aFlags == kODIdentityXform)
  652.         return false;
  653.     if (bFlags == kODIdentityXform)
  654.     {    *b = *a;
  655.         return false;
  656.     }
  657.     if (bFlags != kODPerspectiveXform && aFlags < kODScaleXform)
  658.     {    ODPoint hk = *(ODPoint *)&b->m[2][0];
  659.         if (FixAddCheck(a->m[2][0], &b->m[2][0]) || FixAddCheck(a->m[2][1], &b->m[2][1]))
  660.         {    *(ODPoint *)&b->m[2][0] = hk;
  661.             goto rangeError;
  662.         }
  663.         return false;
  664.     }
  665.     if (aFlags < kODLinearXform)
  666.     {    register fastInt i, j;
  667.         oldB = *b;
  668.         savedB = true;
  669.         for (i = 3; i--; )
  670.             for (j = 2; j--; )
  671.             {    if (aFlags >= kODScaleXform)
  672.                     if (FixMulCheck(b->m[i][j], a->m[j][j], &b->m[i][j]))
  673.                         goto rangeError;
  674.                 if (aFlags & kODTranslateXform)
  675.                     if (i == 2) {
  676.                         if (bFlags == kODPerspectiveXform) {
  677.                             if (FracMulAddCheck(b->m[2][2], a->m[2][j], &b->m[2][j]))
  678.                                 goto rangeError;
  679.                         } else if (FixAddCheck(a->m[2][j], &b->m[2][j]))
  680.                             goto rangeError;
  681.                     } else if (bFlags == kODPerspectiveXform)
  682.                         if (FracMulAddCheck(b->m[i][2], a->m[2][j], &b->m[i][j]))
  683.                             goto rangeError;
  684.             }
  685.         return false;
  686.     }
  687.     if (aFlags < kODPerspectiveXform)
  688.     {    
  689.         ODMatrix c;
  690.         register fastInt i, j;
  691.         for (i = 3; i--; )
  692.         {    c.m[i][2] = b->m[i][2];
  693.             for (j = 2; j--; )
  694.             {    if (aFlags >= kODScaleXform)
  695.                 {    if (FixMulCheck(b->m[i][j], a->m[j][j], &c.m[i][j]))
  696.                         goto rangeError;
  697.                     if (aFlags >= kODLinearXform)
  698.                         if (FixMulAddCheck(b->m[i][1-j], a->m[1-j][j], &c.m[i][j]))
  699.                             goto rangeError;
  700.                 }
  701.                 else
  702.                     c.m[i][j] = b->m[i][j];
  703.                 if (aFlags & kODTranslateXform)
  704.                     if (i == 2) {
  705.                         if (bFlags == kODPerspectiveXform) {
  706.                             if (FracMulAddCheck(b->m[2][2], a->m[2][j], &c.m[2][j]))
  707.                                 goto rangeError;
  708.                         } else
  709.                             if (FixAddCheck(a->m[2][j], &c.m[2][j]))
  710.                                 goto rangeError;
  711.                     } 
  712.                       else if (bFlags == kODPerspectiveXform)
  713.                         if (FracMulAddCheck(b->m[i][2], a->m[2][j], &c.m[i][j]))
  714.                             goto rangeError;
  715.             }
  716.         }
  717.         *b = c;
  718.         return false;
  719.     }
  720. perspectiveCase:    /* aFlags == kODPerspectiveXform */
  721.     {    ODWide c[3][3];
  722.         register fastInt i, j;
  723.         bias delta = { 16, 16, 16, 16 };
  724.         for (i = 3; i--; )
  725.             for (j = 3; j--; )
  726.             {    ODWide temp;
  727.                 ODWideShift(ODWideMultiply(b->m[i][2], a->m[2][j], &c[i][j]), fractPrecision - fixedPrecision);
  728.                 ODWideAdd(&c[i][j], ODWideMultiply(b->m[i][1], a->m[1][j], &temp));
  729.                 ODWideAdd(&c[i][j], ODWideMultiply(b->m[i][0], a->m[0][j], &temp));
  730.             }
  731.         return MxWideNorm(c, b, &delta);
  732.     }
  733.  
  734. rangeError:
  735.     if (savedB) *b = oldB;
  736.     goto perspectiveCase;
  737. }
  738.  
  739.  
  740. /*                                        |  1   0   0    |
  741.     currentMatrix =  currentMatrix *    |  0   1   0    |
  742.                                         |  tx  ty  1    |
  743. */
  744. ODBoolean
  745. MxMove(ODMatrix *currentMatrix, ODTransformType flags, register ODFixed tx, register ODFixed ty)
  746. {
  747.     if (flags == kODPerspectiveXform)
  748.     {    register ODFixed *fixPtr = ¤tMatrix->m[0][0];
  749.         register ODFract *fracPtr = ¤tMatrix->m[0][2];
  750.         register fastInt counter = 3;
  751.         
  752.         do
  753.         {    register ODFract u = fracPtr[0];
  754.         
  755.             if (FracMulAddCheck(u, tx, &fixPtr[0]) || FracMulAddCheck(u, ty, &fixPtr[1]))
  756.                 return true;
  757.             fracPtr += 3;
  758.             fixPtr += 3;
  759.         } while (--counter);
  760.     } else if (FixAddCheck(tx, ¤tMatrix->m[2][0]) || FixAddCheck(ty, ¤tMatrix->m[2][1]))
  761.         return true;
  762.     return false;
  763. }
  764.  
  765.  
  766. ODBoolean
  767. MxMoveTo(register ODMatrix *currentMatrix, ODTransformType flags, ODFixed x, ODFixed y)
  768. {
  769.     if (flags == kODPerspectiveXform)
  770.     {    register ODFract u = currentMatrix->m[2][2];
  771.         
  772.         if (FracDivAddCheck(-currentMatrix->m[2][0], u, &x) ||
  773.             FracDivAddCheck(-currentMatrix->m[2][1], u, &y))
  774.         {
  775.             return true;
  776.         } 
  777.         return MxMove(currentMatrix, kODPerspectiveXform, x, y);
  778.     } else
  779.     {    register ODFixed *fixPtr = ¤tMatrix->m[2][0];
  780.     
  781.         *fixPtr++ = x;
  782.         *fixPtr = y;
  783.     }
  784.     return false;
  785. }
  786.  
  787. /*
  788.  * scales a matrix by sx and sy.
  789.  *
  790.  *                                | sx 0   0    |
  791.  *    currentMx =  currentMx *    | 0   sy 0    |;
  792.  *                                | 0   0  1    |
  793.  *
  794.  */
  795. ODBoolean
  796. MxScale(ODMatrix *currentMatrix, register ODFixed sx, register ODFixed sy)
  797. {    
  798.     register ODFixed *m = currentMatrix->m[0];
  799.     
  800.     if (FixMulCheck( sx, *m, m))
  801.         return true;
  802.     m++;
  803.     if (FixMulCheck( sy, *m, m))
  804.         return true;
  805.     m += 2;
  806.     if (FixMulCheck( sx, *m, m))
  807.         return true;
  808.     m++;
  809.     if (FixMulCheck( sy, *m, m))
  810.         return true;
  811.     m += 2;
  812.     if (FixMulCheck( sx, *m, m))
  813.         return true;
  814.     m++;
  815.     if (FixMulCheck( sy, *m, m))
  816.         return true;
  817.     return false;
  818. }
  819.  
  820.  
  821. /*                                        | 1            ySkew     0    |
  822.     currentMatrix =  currentMatrix *    | xSkew     1        0   |
  823.                                         | 0            0        1   |    */
  824. ODBoolean
  825. MxSkew(ODMatrix *currentMatrix, register ODFixed xSkew, register ODFixed ySkew)
  826. {
  827.     register ODFixed *matrixPtr = currentMatrix->m[0];
  828.     register fastInt counter = 3;
  829.     
  830.     do
  831.     {    register ODFixed temp = *matrixPtr;
  832.         
  833.         if (xSkew)
  834.             if (FixMulAddCheck(*(matrixPtr+1), xSkew, matrixPtr))
  835.                 return true;
  836.         matrixPtr += 1;
  837.         if (ySkew)
  838.             if (FixMulAddCheck(temp, ySkew, matrixPtr))
  839.                 return true;
  840.         matrixPtr += 2;
  841.     } while (--counter);
  842.     return false;
  843. }
  844.  
  845.  
  846. /*                                    | cosine    sine      0    |
  847.     currentMatrix = currentMatrix *    | -sine        cosine  0    | 
  848.                                     | 0            0        1    |    */
  849. /* note that while this would almost never fail, in extreme pathological cases, it could , for */
  850. /* instance if the ODMatrix [0][0] and [0][1] are both > ff(23200) */
  851. ODBoolean
  852. MxRotate(ODMatrix *currentMatrix, ODFixed angle)
  853. {
  854.     ODFract cos;
  855.     register ODFract s = ODFractSinCos(angle, &cos);
  856.     register ODFract c = cos;
  857.     register ODFixed *src = currentMatrix->m[0];
  858.     register ODFixed *dst = src;
  859.     register fastInt counter = 3;    
  860.  
  861.     do
  862.     {    register ODFixed x = *src++;
  863.         register ODFixed y = *src;
  864.         
  865.         src += 2;
  866.         *dst = FracMul(x, c);
  867.         if (FracMulAddCheck(y, -s, dst++))
  868.             return true;
  869.         *dst = FracMul(x, s);
  870.         if (FracMulAddCheck(y, c, dst)) 
  871.             return true;
  872.         dst += 2;
  873.     } while (--counter);
  874.     return false;
  875. }
  876.